package com.knirirr.beecountclassic;

import java.util.ArrayList;
import java.util.Iterator;
import org.apache.commons.lang3.StringUtils;

import android.annotation.TargetApi;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import java.io.File;


public class EditprojActivity extends Activity implements OnClickListener
{
  static final String TAG = "BeeCountEdit";
  static final String JOIN = "#-#-#";

  DbHelper dbHelper;
  SQLiteDatabase db;
  Button addCountButton;
  Button saveEditButton;
  Button addLinkButton;
  ViewGroup layout;
  TextView titleEditing;
  String projName;
  String duplicate;
  long projId;
  Cursor cursor;
  LinearLayout curr_row; // for deleting table rows
  RelativeLayout curr_link; // for deleting link
  String c_name; // as curr_row
  String middle_name; // as curr_row
  AlertDialog alert; // as curr_row
  long newcount; // number of new boxes added
  int linkcount; // number of links added
  ArrayList<String> entries;
  ArrayList<String> links;
  Typeface font;
  ActionBar actionBar;
  Intent intent;
  SharedPreferences prefs;
  Boolean fontPref;
  String notes;


  @Override
  @SuppressWarnings("deprecation")
  @TargetApi(14)
  public void onCreate(Bundle savedInstanceState)
  {
    if (android.os.Build.VERSION.SDK_INT < 11)
    {
      setTheme(android.R.style.Theme_NoTitleBar);
    }
    super.onCreate(savedInstanceState);
    setContentView(R.layout.editing);
    Log.i(TAG, "Edit Project");
    duplicate = this.getString(R.string.duplicate); 
    newcount = 1;
    linkcount = 1;
    entries = new ArrayList<String>();
    links = new ArrayList<String>();
    if (android.os.Build.VERSION.SDK_INT > 13)
    {
      actionBar = getActionBar();                                                                                         
      actionBar.setHomeButtonEnabled(true);                                                                               
    }

    // background
    prefs = PreferenceManager.getDefaultSharedPreferences(this);
    String backgroundPref = prefs.getString("pref_back", "default");
    fontPref = prefs.getBoolean("pref_font", true);
    String pictPref = prefs.getString("imagePath", "");

    LinearLayout fulllayout = (LinearLayout) findViewById(R.id.editingScreen);
    if (backgroundPref.equals("none"))
    {
       // boring black screen
    }
    else if (backgroundPref.equals("custom"))
    {
      if (!(pictPref.equals(""))) 
      {
        if (new File(pictPref).isFile())
        {
          try
          {
            fulllayout.setBackgroundDrawable(BackgroundImage.decodeSampledBitmapFromResource(pictPref,EditprojActivity.this));
          }
          catch (OutOfMemoryError e)
          {
            Log.e(TAG, "OOM error: " + e);
            Toast.makeText(this,getString(R.string.customTooBig),Toast.LENGTH_SHORT).show();
            fulllayout.setBackgroundResource(R.drawable.beecount_knitting);
          }
        }
        else
        {
          Toast.makeText(this,getString(R.string.customMissing),Toast.LENGTH_SHORT).show();
          fulllayout.setBackgroundResource(R.drawable.beecount_knitting);
        }
      }
      else
      {
        Toast.makeText(this,getString(R.string.customNotDefined),Toast.LENGTH_SHORT).show();
        fulllayout.setBackgroundResource(R.drawable.beecount_knitting);
      }
    }
    else if (backgroundPref.equals("default"))
    {
      fulllayout.setBackgroundResource(R.drawable.beecount_knitting);
    } 


    // fancy font
    if (fontPref == true)
    {
      font = Typeface.createFromAsset(getAssets(), "village.ttf"); 
    }

    // various buttons
    addCountButton = (Button) findViewById(R.id.addCountButton);
    saveEditButton = (Button) findViewById(R.id.saveEditButton);
    addLinkButton = (Button) findViewById(R.id.addLinkButton);
    addCountButton.setTag("addCountButton");
    saveEditButton.setTag("saveEditButton");
    addLinkButton.setTag("addLinkButton");
    addCountButton.setOnClickListener(this);
    saveEditButton.setOnClickListener(this);
    addLinkButton.setOnClickListener(this);
    if (fontPref == true)
    {
      addCountButton.setTypeface(font);
      saveEditButton.setTypeface(font);
      addLinkButton.setTypeface(font);
    }

    layout = (LinearLayout) findViewById(R.id.countEditLayout);

    //Read more: http://getablogger.blogspot.com/2008/01/android-pass-data-to-activity.html#ixzz1lhGnzZpZ
    Bundle extras = getIntent().getExtras(); 
    if(extras !=null)
    {
      projName = extras.getString("projName");
      projId = extras.getLong("projId");
    }
    
    /* 
     * before anything else happens, the layout must be completed
     * by drawing boxes for the various components of the project
     */

    // title &c.
    titleEditing = (EditText) findViewById(R.id.titleEditing);
    titleEditing.setText(projName.replaceAll("(^')|('$)","").replaceAll("''","'"));
    if (fontPref == true)
    {
      titleEditing.setTypeface(font);
    }

    
    // get database
    dbHelper = new DbHelper(this);
    db = dbHelper.getReadableDatabase();

    Log.i(TAG,"Starting up!");

    // query database for the data
    cursor = db.query(DbHelper.COUNT_TABLE, new String[] {DbHelper.C_NAME, DbHelper.C_COUNT}, DbHelper.C_PROJECT_ID + "=?", new String[] { String.valueOf(projId) }, null, null, null); // stuff
    startManagingCursor(cursor);

    // get the data, display and that
    String name;
    long value;
    while (cursor.moveToNext())
    {
      name = cursor.getString(cursor.getColumnIndex(DbHelper.C_NAME));      
      value = cursor.getLong(cursor.getColumnIndex(DbHelper.C_COUNT));      
      //Log.i(TAG,"Name: " + name + ", Value: " + value);

      // now create some new objects and layouts
      LinearLayout row = new LinearLayout(this);
      row.setOrientation(0);
      row.setTag(name + "_row");
      row.setGravity(Gravity.CENTER_VERTICAL);

      LinearLayout.LayoutParams left = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT,Gravity.LEFT | Gravity.CENTER_VERTICAL);
      //LinearLayout.LayoutParams right = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT,Gravity.RIGHT | Gravity.CENTER_VERTICAL);

      EditText title = new EditText(this);
      title.setText(name);
      title.setTextSize(TypedValue.COMPLEX_UNIT_DIP,20);
      title.setHorizontallyScrolling(true);
      title.setTag(name + "_name");
      title.setLayoutParams(left);
      title.setHorizontallyScrolling(true);
      title.setGravity(Gravity.CENTER);

      EditText counting = new EditText(this);
      counting.setText(String.valueOf(value));
      counting.setTag(name + "_count");
      counting.setTextSize(TypedValue.COMPLEX_UNIT_DIP,20);
      counting.setGravity(Gravity.CENTER);
       
      Button deleteCount = new Button(this);
      deleteCount.setText(R.string.deleteCount);
      deleteCount.setOnClickListener(this);
      deleteCount.setTag(name + "_delete");
      if (fontPref == true)
      {
        deleteCount.setTypeface(font);
      }
      deleteCount.setGravity(Gravity.CENTER); // no idea how this works
      //deleteCount.setWidth(120);

      row.addView(title);
      row.addView(counting);
      row.addView(deleteCount);
      layout.addView(row,new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
      entries.add(name);
    }

    // add links between counts here
    String master;
    String slave;
    long increment;
    long type;
    cursor = db.query(DbHelper.LINK_TABLE, new String[] {DbHelper.L_MASTER, DbHelper.L_SLAVE,DbHelper.L_INCREMENT,DbHelper.L_TYPE}, DbHelper.L_PROJECT_ID + "=?", new String[] { String.valueOf(projId) }, null, null, null); // stuff
    startManagingCursor(cursor);
    while (cursor.moveToNext())
    {
      master = cursor.getString(cursor.getColumnIndex(DbHelper.L_MASTER));      
      slave = cursor.getString(cursor.getColumnIndex(DbHelper.L_SLAVE));      
      increment = cursor.getLong(cursor.getColumnIndex(DbHelper.L_INCREMENT));      
      type = cursor.getLong(cursor.getColumnIndex(DbHelper.L_TYPE));      

      LinearLayout currLink = new LinearLayout(this);
      currLink.setOrientation(0);
      currLink.setTag("old_" + master + JOIN + slave + "_link");
      currLink.setGravity(Gravity.CENTER_VERTICAL);

      TextView summary = new TextView(this);
      String incr;
      if (type == 0)
      {
        incr = getString(R.string.incr_reset);
      }
      else
      {
        incr = getString(R.string.incr);
      }

      String ev = getString(R.string.ev);
      summary.setText(truncate(master,7) + " " + incr + " " + truncate(slave,7) + " "  + ev + " " + String.valueOf(increment)); // long values push the button off screen
      summary.setTextSize(TypedValue.COMPLEX_UNIT_DIP,12);
      if (fontPref == true)
      {
        summary.setTypeface(font);
      }
      summary.setTextColor(Color.WHITE);
      summary.setHorizontallyScrolling(true);

      Button unlink = new Button(this);
      unlink.setText(R.string.removeLink);
      unlink.setOnClickListener(this);
      unlink.setTag("link_" + master + JOIN + slave + "_delete");
      if (fontPref == true)
      {
        unlink.setTypeface(font);
      }
      unlink.setTextSize(TypedValue.COMPLEX_UNIT_DIP,12);

      currLink.addView(summary);
      currLink.addView(unlink);

      layout.addView(currLink,new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
    }

    // divider
    TextView notesHere = new TextView(this);
    notesHere.setText(R.string.notesHere);
    if (fontPref == true)
    {
      notesHere.setTypeface(font);
    }
    notesHere.setTextColor(Color.WHITE);
    layout.addView(notesHere,new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));

    // finally, the adding of a edit box giving the project notes might be a good thing to have
    cursor = db.query(DbHelper.PROJ_TABLE, new String[] {DbHelper.P_NOTES,}, DbHelper.P_ID + "=?", new String[] { String.valueOf(projId) }, null, null, null); // stuff
    startManagingCursor(cursor);

    while (cursor.moveToNext())
    {
      notes = cursor.getString(cursor.getColumnIndex(DbHelper.P_NOTES));      
    }

    EditText note_view = new EditText(this);
    note_view.setTag("note_view");
    if (fontPref == true)
    {
      note_view.setTypeface(font);
    }
    note_view.setTextColor(Color.WHITE);
    note_view.setPadding(10,10,10,10);
    if (!StringUtils.isBlank(notes))
    {
      note_view.setText(notes); 
    }
    layout.addView(note_view,new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
  }

  // a menu for editing and deleting projects
  @Override
  @TargetApi(14)
  public boolean onCreateOptionsMenu(Menu menu)
  {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.editmenu, menu);
    if (android.os.Build.VERSION.SDK_INT > 13)
    {
      actionBar = getActionBar();                                                                                         
      actionBar.setHomeButtonEnabled(true);                                                                               
    }
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item)
  {
    switch (item.getItemId())
    {
      case android.R.id.home:
        startActivity(new Intent(this, WelcomeActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
        break;
      case R.id.editHelp:
        intent = new Intent(this,EditHelpActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        startActivity(intent);
        break;
      default:
        return super.onOptionsItemSelected(item);
    }
    return true;
  }

  public void onClick(View view)
  {
    String viewTag = (String) view.getTag();
    if (viewTag.equals("saveEditButton"))
    {
      saveProject();
    }
    else if (viewTag.equals("addCountButton"))
    {
      addCount();
    }
    else if (viewTag.equals("addLinkButton"))
    {
      addLink();
    }
    else
    {
      Log.i(TAG,"CLICK: " + viewTag); 
      String[] clicked = viewTag.split("_");
      c_name = clicked[0];
      middle_name = clicked[1];
      if (c_name.equals("link"))
      {
        if (isNumeric(middle_name))
        {
          curr_link = (RelativeLayout) layout.findViewWithTag("new_" + middle_name + "_link"); // a link between counts
        }
        else
        {
          curr_row = (LinearLayout) layout.findViewWithTag("old_" + middle_name + "_link"); // a link between counts
        }
      }
      else
      {
        curr_row = (LinearLayout) layout.findViewWithTag(c_name + "_row");
      }
      // confirmation dialog + delete from database
      // http://developer.android.com/guide/topics/ui/dialogs.html#AlertDialog
      AlertDialog.Builder builder = new AlertDialog.Builder(this);
      builder.setIcon(android.R.drawable.ic_dialog_alert);
      builder.setMessage(R.string.confirmDelete).setCancelable(false).setPositiveButton(R.string.yesButton, new DialogInterface.OnClickListener()
      {
        public void onClick(DialogInterface dialog, int id) 
        {
          //Log.i(TAG,"Would have deleted!");
          // http://stackoverflow.com/questions/4095309/sqlite-delete-query-syntax-in-android

          // luckily the rown name contains the original count name and so there shouldn't be a problem if users
          // have altered the value in the box before deleting the line
          if (c_name.equals("link"))
          {
            // delete from link table
            if (isNumeric(middle_name))
            {
              layout.removeView(curr_link);
            }
            else
            {
              // parse middle_name to get master and slave info.
              String[] ms = middle_name.split(JOIN);
              try 
              {
                db.execSQL("delete from " + DbHelper.LINK_TABLE + " where " + DbHelper.L_PROJECT_ID + " = " + projId + " and " + DbHelper.L_MASTER + " = \'" + ms[0] + "\' and " + DbHelper.L_SLAVE + " = \'" + ms[1] + "\'" );
              }
              catch (Exception e)
              {
                db.execSQL("delete from " + DbHelper.LINK_TABLE + " where " + DbHelper.L_PROJECT_ID + " = " + projId);
                Log.e(TAG, "Failed to delete link entry: " + e);
                Toast.makeText(EditprojActivity.this, getString(R.string.randomFail),Toast.LENGTH_SHORT).show();
              }
              layout.removeView(curr_row);
            }
            links.remove("new_" + middle_name + "_link");
          }
          else
          {
            db.execSQL("delete from " + DbHelper.COUNT_TABLE + " where " + DbHelper.C_PROJECT_ID + " = " + projId + " and " + DbHelper.C_NAME + " = \'" + c_name + "\'");
            entries.remove(c_name);
            layout.removeView(curr_row);
          }
        }
      }).setNegativeButton(R.string.noButton, new DialogInterface.OnClickListener() 
      {
        public void onClick(DialogInterface dialog, int id) 
        {
          dialog.cancel();
        }
      });
      alert = builder.create();
      alert.show();
    }
  }

  public static boolean isNumeric(String str)  
  {  
    try  
    {  
      double d = Double.parseDouble(str);  
      Log.e(TAG,"Row no. " + String.valueOf(d));
    }  
    catch(NumberFormatException nfe)  
    {  
      return false;  
    }  
    return true;  
  }


  @Override
  protected void onPause()
  {
    super.onPause();
    // don't save here, causes double insertion of new values
  }

  private void addCount()
  {
    // add a new box a bit like we see in the initial setup...
    // now create some new objects and layouts
    LinearLayout row = new LinearLayout(this);
    row.setOrientation(0);
    row.setTag("new" + newcount + "_row");
    row.setGravity(Gravity.CENTER_VERTICAL);

    LinearLayout.LayoutParams left = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT,Gravity.LEFT | Gravity.CENTER_VERTICAL);

    EditText title = new EditText(this);
    title.setTextSize(TypedValue.COMPLEX_UNIT_DIP,20);
    title.setHorizontallyScrolling(true);
    title.setGravity(Gravity.CENTER);
    title.setTag("new" + newcount + "_name");
    title.setLayoutParams(left);

    EditText counting = new EditText(this);
    counting.setText(String.valueOf(0));
    counting.setTag("new" + newcount + "_count");
    counting.setGravity(Gravity.CENTER);
    counting.setTextSize(TypedValue.COMPLEX_UNIT_DIP,20);


    Button deleteCount = new Button(this);
    deleteCount.setText(R.string.deleteCount);
    deleteCount.setOnClickListener(this);
    deleteCount.setTag("new" + newcount + "_delete");
    if (fontPref == true)
    {
      deleteCount.setTypeface(font);
    }
    //deleteCount.setWidth(120);

    row.addView(title);
    row.addView(counting);
    row.addView(deleteCount);
    layout.addView(row,new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    entries.add("new" + newcount);
    newcount = newcount + 1;
  }

  /*
   * this section will link one count (the "master") to another (the "slave")
   * RelativeLayout
   * Spinner  TextView (will increment)
   * Spinner  TextView (on every), EditText (number)
   */
  private void addLink()
  {

    RelativeLayout link = new RelativeLayout(this);
    RelativeLayout.LayoutParams lp_master = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    RelativeLayout.LayoutParams lp_slave = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    RelativeLayout.LayoutParams lp_instruction = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    RelativeLayout.LayoutParams lp_every = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    RelativeLayout.LayoutParams lp_number = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    RelativeLayout.LayoutParams lp_button = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);

    link.setTag("new_" + linkcount + "_link");
    link.setGravity(Gravity.CENTER_VERTICAL);

    ArrayList<String> texts = new ArrayList<String>();
    int childcount = layout.getChildCount();
    for (int i=0; i < childcount; i++)
    {
      View ll = layout.getChildAt(i);
      //Log.i("TAGS: ", (String) ll.getTag());
      if (StringUtils.contains((String) ll.getTag(),"_row"))
      {
        LinearLayout ll2 = (LinearLayout) ll;
        // I have no idea what caused this error and can't manage to replicate it;
        // therefore, if it happens again this should at least prevent the app from crashing
        EditText v;
        int llchildcount = ll2.getChildCount();
        for (int j=0; j < llchildcount; j++)
        {
          View ll3 = ll2.getChildAt(j);
          if (StringUtils.contains((String) ll3.getTag(),"_name"))
          {
            try
            {
              v = (EditText) ll3;
              texts.add(v.getText().toString());
              break;
            }
            catch (Exception e)
            {
              Toast.makeText(EditprojActivity.this, getString(R.string.randomFail),Toast.LENGTH_SHORT).show();
              return;
            }
          }
        }
      }
    }
    

    // http://stackoverflow.com/questions/5483495/how-to-set-font-custom-font-to-spinner-text-programmatically
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.custom_spinner, texts) 
    {
      public View getView(int position, View convertView, ViewGroup parent) 
      {
        View v = super.getView(position, convertView, parent);
        if (fontPref == true)
        { 
          ((TextView) v).setTypeface(font);
        }
        if (android.os.Build.VERSION.SDK_INT > 10)
        {
          ((TextView) v).setTextColor(Color.WHITE);
        }
        return v;
      }
      public View getDropDownView(int position,  View convertView,  ViewGroup parent) 
      {
        View v =super.getDropDownView(position, convertView, parent);
        if (fontPref == true)
        {
          ((TextView) v).setTypeface(font);
        }
        if (android.os.Build.VERSION.SDK_INT > 10)
        {
          ((TextView) v).setTextColor(Color.WHITE);
        }
        return v;
      }
    };

    ArrayList<String> instructions = new ArrayList<String>();
    instructions.add(this.getString(R.string.instruction));
    instructions.add(this.getString(R.string.instruction_reset));

    ArrayAdapter<String> adapter_instr = new ArrayAdapter<String>(this, R.layout.custom_spinner, instructions) 
    {
      public View getView(int position, View convertView, ViewGroup parent) 
      {
        View v = super.getView(position, convertView, parent);
        if (fontPref == true)
        {
          ((TextView) v).setTypeface(font);
        }
        if (android.os.Build.VERSION.SDK_INT > 10)
        {
          ((TextView) v).setTextColor(Color.WHITE);
        }
        return v;
      }
      public View getDropDownView(int position,  View convertView,  ViewGroup parent) 
      {
        View v =super.getDropDownView(position, convertView, parent);
        if (fontPref == true)
        {
          ((TextView) v).setTypeface(font);
        }
        if (android.os.Build.VERSION.SDK_INT > 10)
        {
          ((TextView) v).setTextColor(Color.WHITE);
        }
        return v;
      }
    };

    Spinner master = new Spinner(this);
    master.setId(1);
    master.setTag(linkcount + "_master");
    master.setAdapter(adapter);
    lp_master.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    lp_master.addRule(RelativeLayout.ALIGN_PARENT_TOP);

    Spinner instruction = new Spinner(this);
    instruction.setId(2);
    instruction.setTag(linkcount + "_instruction");
    instruction.setAdapter(adapter_instr);
    lp_instruction.addRule(RelativeLayout.RIGHT_OF, master.getId());

    Spinner slave = new Spinner(this);
    slave.setId(3);
    slave.setTag(linkcount + "_slave");
    slave.setAdapter(adapter);
    lp_slave.addRule(RelativeLayout.BELOW, master.getId());
    lp_slave.addRule(RelativeLayout.ALIGN_PARENT_LEFT);

    TextView every = new TextView(this);
    every.setId(4);
    every.setText(this.getString(R.string.every));
    every.setTextSize(TypedValue.COMPLEX_UNIT_DIP,25);
    if (fontPref == true)
    {
      every.setTypeface(font);
    }
    every.setTextColor(Color.WHITE);
    lp_every.addRule(RelativeLayout.BELOW, master.getId());
    lp_every.addRule(RelativeLayout.RIGHT_OF, slave.getId());

    EditText number = new EditText(this);
    number.setId(5);
    number.setTag(linkcount + "_number");
    number.setText(String.valueOf(1));
    lp_number.addRule(RelativeLayout.BELOW, master.getId());
    lp_number.addRule(RelativeLayout.RIGHT_OF, every.getId());
    
    Button removeLink = new Button(this);
    removeLink.setId(6);
    removeLink.setTag("link_" + linkcount + "_delete");
    removeLink.setText(this.getString(R.string.removeLink));
    if (fontPref == true)
    {
      removeLink.setTypeface(font);
    }
    lp_button.addRule(RelativeLayout.BELOW, slave.getId());
    lp_button.addRule(RelativeLayout.CENTER_IN_PARENT);
    removeLink.setOnClickListener(this);

    link.addView(master,lp_master);
    link.addView(instruction,lp_instruction);
    link.addView(slave,lp_slave);
    link.addView(every,lp_every);
    link.addView(number,lp_number);
    link.addView(removeLink,lp_button);

    layout.addView(link); 
    links.add("new_" + linkcount + "_link");
    linkcount++;
      
  }

  private void saveProject()
  {
    // check that a project name is supplied
    EditText titleEdit = (EditText) findViewById(R.id.titleEditing);
    projName = titleEdit.getText().toString().replaceAll("(^')|('$)","").replaceAll("''","'");
    Log.i(TAG, "Got project name: " + projName);

    // argh, iterate over table rows twice, first to check they're
    // not empty, then to perform the update...
    ArrayList<String> countNames = new ArrayList<String>();
    ArrayList<EditText> myTexts = new ArrayList<EditText>();
    myTexts.add(titleEdit);
    int carryon = 1;
    Iterator<String> itr = entries.iterator();       
    while(itr.hasNext())
    {
      String origname = itr.next();
      EditText newname = (EditText) layout.findViewWithTag(origname + "_name");
      myTexts.add(newname);
      EditText newcount = (EditText) layout.findViewWithTag(origname + "_count");
      String errorcheck;
      errorcheck = newname.getText().toString();
      if (StringUtils.isBlank(errorcheck))
        carryon = 0;
      errorcheck = newcount.getText().toString();
      if (StringUtils.isBlank(errorcheck))
        carryon = 0;
    }

    // check that user hasn't added any duplicate names in the counts
    // check for unique names                                                                                             
    for (EditText c : myTexts)
    {
      String count_name = c.getText().toString();
      if (countNames.contains(count_name)) 
      {
        Toast.makeText(this,duplicate,Toast.LENGTH_SHORT).show();
        return;
      }
      else
      {
        countNames.add(count_name);
      }
    }

    // are there any new counts
    Iterator<String> itr2 = links.iterator();       
    String message = "";
    while(itr2.hasNext())
    {
      String name = itr2.next();
      String[] clicked = name.split("_");
      //Log.i(TAG,"LINK: " + name);
      Spinner master = (Spinner) layout.findViewWithTag(clicked[1] + "_master");
      Spinner slave = (Spinner) layout.findViewWithTag(clicked[1] + "_slave");
      EditText number = (EditText) layout.findViewWithTag(clicked[1] + "_number");

      try
      {
        if (master.getSelectedItem().toString().equals(slave.getSelectedItem().toString()))
        {
          carryon = 0;
          message = getString(R.string.mismatch);
        }
      }
      catch (Exception e)
      {
        carryon = 0;
        message = getString(R.string.failedToSave);
      }

      try 
      {
        if (Integer.parseInt(number.getText().toString()) <= 0)
        {
          carryon = 0;
          message = getString(R.string.zero);
        }
      }
      catch (Exception e)
      {
        carryon = 0;
        message = getString(R.string.integer);
      }
    }

    if (carryon == 0)
    {
      // warning toast - please check and try again
      Toast.makeText(this, message,Toast.LENGTH_SHORT).show();
      Log.i(TAG, "Update failed!");
      return;
    }

    // update
    // get a database connection
    dbHelper = new DbHelper(this);
    db = dbHelper.getWritableDatabase();
    itr = entries.iterator();       
    while(itr.hasNext())
    {
      String origname = itr.next();
      EditText newname = (EditText) layout.findViewWithTag(origname + "_name");
      String name = newname.getText().toString();
      EditText newcount = (EditText) layout.findViewWithTag(origname + "_count");
      long count = 0;
      try 
      {
        count = Long.parseLong(newcount.getText().toString());
      }
      catch (Exception e)
      {
        Toast.makeText(EditprojActivity.this, getString(R.string.dodgyFormat),Toast.LENGTH_SHORT).show();
        return;
      }


      // if a new count has been added then the update must be treated differently
      ContentValues values = new ContentValues();
      values.put(DbHelper.C_PROJECT_ID,projId);
      values.put(DbHelper.C_NAME,name.replaceAll("_","-").replaceAll("'","\'"));
      values.put(DbHelper.C_COUNT,count);       
      if (StringUtils.contains(origname,"new"))
      {
        // create new line
        db.insertOrThrow(DbHelper.COUNT_TABLE,null,values);
        //Log.i("INSERT NEW", values.toString());
      }
      else
      {
        // update existing
        String tmporigname = origname.replaceAll("'","''");
        db.update(DbHelper.COUNT_TABLE, values, DbHelper.C_PROJECT_ID + "=" + projId + " and " + DbHelper.C_NAME + "= '" + tmporigname + "'", null);
        Log.i("UPDATE EXISTING", values.toString());
      }
      //Log.i("WOULD UPDATE: ", name + "," + count);
    }
    // now the links
    itr2 = links.iterator();       
    while(itr2.hasNext())
    {
      String name = itr2.next();
      String[] clicked = name.split("_");
      Spinner master = (Spinner) layout.findViewWithTag(clicked[1] + "_master");
      Spinner slave = (Spinner) layout.findViewWithTag(clicked[1] + "_slave");
      Spinner instruction = (Spinner) layout.findViewWithTag(clicked[1] + "_instruction");
      EditText number = (EditText) layout.findViewWithTag(clicked[1] + "_number");
      // if a new link has been added then the update must be treated differently
      ContentValues values = new ContentValues();
      values.put(DbHelper.L_PROJECT_ID,projId);
      values.put(DbHelper.L_MASTER,master.getSelectedItem().toString());
      values.put(DbHelper.L_SLAVE,slave.getSelectedItem().toString());       
      values.put(DbHelper.L_INCREMENT,number.getText().toString());       
      if (instruction.getSelectedItem().toString() == this.getText(R.string.instruction))
      {
        values.put(DbHelper.L_TYPE,1);       
      }
      else
      {
        values.put(DbHelper.L_TYPE,0);     
      }
      // create new line
      db.insertOrThrow(DbHelper.LINK_TABLE,null,values);
    }

    // finally, save the project notes and the project name (which may have changed, above)
    // get notes here #####
    EditText note_view = (EditText) layout.findViewWithTag("note_view");
    notes = note_view.getText().toString();
    if (StringUtils.isBlank(notes))
    {
      notes = "";
    }

    ContentValues values = new ContentValues();
    values.put(DbHelper.P_NOTES,notes);
    values.put(DbHelper.P_NAME,projName);
    db.update(DbHelper.PROJ_TABLE, values, DbHelper.P_ID + "=" + projId, null);

    db.close();
    Toast.makeText(this, getString(R.string.projSaving) + " " + projName + "!",Toast.LENGTH_SHORT).show();
    finish(); // return to previous activity
  }



  public static String truncate(String value, int length)
  {
    if (value != null && value.length() > length)
      value = value.substring(0, length) + "...";
    return value;
  }
  
}
  
